# SPDX-FileCopyrightText: 2025 MounRiver Studio <https://mounriverstudio.com/>
# SPDX-License-Identifier: BSD-3-Clause
# Author: Azolla <https://gitee.com/azolla/>
# Date: 2025-04-21

include(${CMAKE_CURRENT_LIST_DIR}/color.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../components/cmake/git-version.cmake)

message(STATUS "${G}CMake version: ${CMAKE_VERSION}${E}")

# add cmake modules path
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) 

# Check for the toolchain path
if(DEFINED ENV{MRS_TOOLCHAIN_PATH})
    set(MRS_TOOLCHAIN_PATH $ENV{MRS_TOOLCHAIN_PATH} CACHE PATH "Path to the MounRiver Studio toolchain" FORCE)
    set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/riscv.toolchain.cmake")
    message(STATUS "${G}MRS_TOOLCHAIN_PATH: ${MRS_TOOLCHAIN_PATH}${E}")
else()
    message(FATAL_ERROR "${R}No supported toolchain found!${E}")
endif()


# add driver directory
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../driver    driver)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../hal       hal)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../utils     utils)
if(CONFIG_FREERTOS)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../FreeRTOS  FreeRTOS)
endif()

# link driver target
function(target_link_compile_options target)
    if(NOT TARGET ${target})
        message(FATAL_ERROR "Target ${target} not found!")
    endif()

    # message(STATUS "LINK_DIR: ${LINK_DIR}")
    if(NOT EXISTS "${LINK_DIR}")
        message(FATAL_ERROR ${R}"Link.ld file not found!"${E})
    endif()
 
    set(compile_options
        -march=rv32imac # 指令集 V4ABC内核 IMAC；V4F内核 IMACF
        -mabi=ilp32     # 指定 ABI
        -Os             # 优化等级 -O0 -O1 -O2 -O3 -Os
        -g0             # 调试信息等级 -g0 -g1 -g3
        -Wall           # 启用所有常见警告
        # -Wextra # 启用所有扩展警告
        # -Wpedantic # 启用所有严格的警告
        # -Werror # 将所有警告视为错误
        -Wshadow # 变量名冲突警告
        -Wformat # 格式化字符串警告
        -Wformat-extra-args # 格式化字符串额外参数警告
        -Wformat-security # 格式化字符串安全性警告
        -Wformat-nonliteral # 格式化字符串非字面值警告
        -Wformat-zero-length # 格式化字符串零长度警告
        -Winit-self     # 初始化自身警告
        -Wmissing-braces # 缺少大括号警告
        # -Wmissing-declarations # 缺少声明警告
        -Wmissing-include-dirs # 缺少包含目录警告
        -ffunction-sections # 将每个函数放在单独的节中
        -fdata-sections # 将每个函数和数据项放在单独的节中
    )
    
    target_compile_options(${target} PRIVATE
        ${compile_options} # 编译选项
    )
 
    target_link_options(${target} PRIVATE
        ${compile_options}  # 编译选项
        # -u _printf_float
        -Wl,-T${LINK_DIR} -nostartfiles -Xlinker --gc-sections # 链接脚本
        -Wl,-Map=$<TARGET_FILE:${target}>.map # 生成.map文件
        -Wl,--print-memory-usage    # 打印内存使用情况
        -Wl,--gc-sections           # 删除未使用的代码
        -Wl,--no-check-sections     # 不检查段
    )
 

    # 烧写固件：cmake --build build --target program
    add_custom_target(
        program
        COMMAND
            ${RISCV_OPENOCD}
            -f ${RISCV_OPENOCD_CONFIG}
            -c init
            -c halt
            #-c "flash erase_sector wch_riscv 0 last"
            -c "program \"$<TARGET_FILE:${target}>\" verify"
            -c wlink_reset_resume
            -c exit
        DEPENDS $<TARGET_FILE:${target}>
    )
 
    # 生成.bin和.hex文件
    add_custom_command(TARGET ${target} POST_BUILD
        COMMAND ${CMAKE_OBJCOPY} -O ihex   $<TARGET_FILE:${target}> ${target}.hex   # 生成.hex文件
        COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${target}> ${target}.bin   # 生成.bin文件
        COMMAND ${CMAKE_OBJDUMP} -h -S $<TARGET_FILE:${target}>  >  ${target}.lst   # 生成.lst文件
        COMMAND ${RISCV_SIZE} --format=berkeley $<TARGET_FILE:${target}>            # 显示固件大小
        COMMENT "Generating ${target}.bin and ${target}.hex files"
    )

    message(STATUS "${C}Generating: ${G}${target}.bin${E} | ${G}${target}.hex${E}")

endfunction()

# 解析 prj.conf 文件生成 prjconf.h 文件
function(add_command_prj2conf)
    # 初始化 prjconf.h 文件内容
    set(PRJCONF_H_CONTENT "#ifndef INCLUDE_PRJCONF_H_\n#define INCLUDE_PRJCONF_H_\n\n")
    # 递归搜索项目目录下的所有 prj.conf 文件
    file(GLOB_RECURSE PRJ_CONF_FILES "${CMAKE_SOURCE_DIR}/**/prj.conf")
    # 检查 CMake 脚本同级目录下的 prj.conf 文件是否存在
    set(LOCAL_PRJ_CONF "${CMAKE_CURRENT_LIST_DIR}/prj.conf")
    if(EXISTS ${LOCAL_PRJ_CONF})
        list(APPEND PRJ_CONF_FILES ${LOCAL_PRJ_CONF})
    endif()
    # 遍历解析所有 prj.conf 文件转为 prjconf.h 文件
    foreach(PRJ_CONF_FILE ${PRJ_CONF_FILES})
        # message(STATUS "${B}Processing: ${PRJ_CONF_FILE}${E}")
        file(STRINGS "${PRJ_CONF_FILE}" PRJ_CONF_LINES)
        foreach(LINE ${PRJ_CONF_LINES})
            if(LINE MATCHES "^CONFIG_([A-Za-z0-9_]+)=(.*)$")
                set(MACRO_NAME  ${CMAKE_MATCH_1})
                set(MACRO_VALUE ${CMAKE_MATCH_2})
                # message(STATUS "${G}Macro: ${MACRO_NAME} = ${MACRO_VALUE}${E}")
                if(MACRO_VALUE STREQUAL "y")
                    add_definitions(-DCONFIG_${MACRO_NAME}=1)
                    set(PRJCONF_H_CONTENT "${PRJCONF_H_CONTENT}#define CONFIG_${MACRO_NAME} 1\n")
                elseif(MACRO_VALUE STREQUAL "n")
                    add_definitions(-DCONFIG_${MACRO_NAME}=0)
                    set(PRJCONF_H_CONTENT "${PRJCONF_H_CONTENT}#define CONFIG_${MACRO_NAME} 0\n")
                else()
                    add_definitions(-DCONFIG_${MACRO_NAME}=${MACRO_VALUE})
                    set(PRJCONF_H_CONTENT "${PRJCONF_H_CONTENT}#define CONFIG_${MACRO_NAME} ${MACRO_VALUE}\n")
                endif()
            endif()
        endforeach()
    endforeach()
    # 将 prjconf.h 文件内容结尾添加保护宏
    set(PRJCONF_H_CONTENT "${PRJCONF_H_CONTENT}\n#endif // INCLUDE_PRJCONF_H_\n")
    # 生成 prjconf.h 文件
    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/include/prjconf.h" "${PRJCONF_H_CONTENT}")

    # 配置项目autoconf.h文件
    configure_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/autoconf.h.in
        ${CMAKE_CURRENT_BINARY_DIR}/include/autoconf.h
    )
 
    # 将生成的 build/prjconf.h 文件所在目录添加到包含路径中
    include_directories("${CMAKE_CURRENT_BINARY_DIR}/../" "${CMAKE_CURRENT_BINARY_DIR}/include")
endfunction()
